package com.harmony.pilot.knowledge.scanner;

import com.harmony.pilot.knowledge.entity.FileMetadata;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;

/**
 * OpenHarmony代码扫描器
 * 深度遍历ohcode目录，支持最多20层深度
 * 提取所有源代码文件的元数据和内容
 */
@Slf4j
@Component
public class CodeScanner {
    
    private static final int MAX_DEPTH = 20;
    private static final long MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB
    
    @Value("${openharmony.code.base-path:../ohcode}")
    private String basePath;
    
    private final Set<String> INCLUDE_EXTENSIONS = new HashSet<>(Arrays.asList(
        ".h", ".hpp", ".cpp", ".cc", ".c", ".gn", ".gni"
    ));
    
    // 特殊文件名称（无扩展名或固定名称）
    private final Set<String> SPECIAL_FILES = new HashSet<>(Arrays.asList(
        "bundle.json", "BUILD.gn"
    ));
    
    private final Set<String> EXCLUDE_PATTERNS = new HashSet<>(Arrays.asList(
        "third_party", "build/out", ".git", "node_modules", ".repo"
    ));
    
    /**
     * 扫描所有代码文件
     */
    public List<FileMetadata> scanAllFiles() throws IOException {
        log.info("开始扫描OpenHarmony代码库: {}", basePath);
        
        List<FileMetadata> files = new ArrayList<>();
        AtomicInteger fileCount = new AtomicInteger(0);
        AtomicInteger skipCount = new AtomicInteger(0);
        
        Path startPath = Paths.get(basePath);
        
        if (!Files.exists(startPath)) {
            log.error("路径不存在: {}", basePath);
            return files;
        }
        
        Files.walkFileTree(startPath, EnumSet.noneOf(FileVisitOption.class), MAX_DEPTH, new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
                // 检查是否应该排除此目录
                String dirName = dir.toString();
                for (String pattern : EXCLUDE_PATTERNS) {
                    if (dirName.contains(pattern)) {
                        log.debug("跳过目录: {}", dir);
                        return FileVisitResult.SKIP_SUBTREE;
                    }
                }
                return FileVisitResult.CONTINUE;
            }
            
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
                try {
                    String fileName = file.getFileName().toString();
                    String extension = getFileExtension(fileName);
                    
                    // 检查文件扩展名或特殊文件名
                    if (!INCLUDE_EXTENSIONS.contains(extension) && !SPECIAL_FILES.contains(fileName)) {
                        return FileVisitResult.CONTINUE;
                    }
                    
                    // 检查文件大小
                    if (attrs.size() > MAX_FILE_SIZE) {
                        log.warn("文件过大，跳过: {} ({}MB)", file, attrs.size() / 1024 / 1024);
                        skipCount.incrementAndGet();
                        return FileVisitResult.CONTINUE;
                    }
                    
                    FileMetadata metadata = createFileMetadataInternal(file, attrs);
                    files.add(metadata);
                    
                    fileCount.incrementAndGet();
                    if (fileCount.get() % 1000 == 0) {
                        log.info("已扫描 {} 个文件...", fileCount.get());
                    }
                    
                } catch (Exception e) {
                    log.error("处理文件失败: {}", file, e);
                }
                return FileVisitResult.CONTINUE;
            }
            
            @Override
            public FileVisitResult visitFileFailed(Path file, IOException exc) {
                log.warn("无法访问文件: {}", file, exc);
                return FileVisitResult.CONTINUE;
            }
        });
        
        log.info("扫描完成! 总共找到 {} 个代码文件，跳过 {} 个", fileCount.get(), skipCount.get());
        return files;
    }
    
    /**
     * 创建文件元数据（公开方法，供ScanService调用）
     */
    public FileMetadata createFileMetadata(Path file, BasicFileAttributes attrs) throws IOException {
        return createFileMetadataInternal(file, attrs);
    }
    
    /**
     * 创建文件元数据（内部实现）
     */
    private FileMetadata createFileMetadataInternal(Path file, BasicFileAttributes attrs) throws IOException {
        FileMetadata metadata = new FileMetadata();
        
        String fullPath = file.toAbsolutePath().toString();
        String relativePath = Paths.get(basePath).toAbsolutePath().relativize(file.toAbsolutePath()).toString();
        
        metadata.setFilePath(fullPath);
        metadata.setRelativePath(relativePath);
        metadata.setFileName(file.getFileName().toString());
        metadata.setFileType(getFileExtension(file.getFileName().toString()));
        metadata.setFileSize(attrs.size());
        metadata.setDepthLevel(calculateDepth(relativePath));
        
        // 提取模块信息
        String[] pathParts = relativePath.split("[\\\\/]");
        if (pathParts.length > 0) {
            metadata.setModuleName(pathParts[0]);
            if (pathParts.length > 1) {
                metadata.setSubModule(pathParts[1]);
            }
        }
        
        // 检查是否是测试/Mock/Fuzzer文件
        String lowerPath = relativePath.toLowerCase();
        metadata.setIsTest(lowerPath.contains("/test/") || lowerPath.contains("/tests/") || 
                           lowerPath.contains("_test.") || lowerPath.contains("test_"));
        metadata.setIsMock(lowerPath.contains("mock") || lowerPath.contains("/mock/"));
        metadata.setIsFuzzer(lowerPath.contains("fuzzer") || lowerPath.contains("/fuzz/"));
        
        // 设置最后修改时间
        metadata.setLastModified(
            LocalDateTime.ofInstant(attrs.lastModifiedTime().toInstant(), ZoneId.systemDefault())
        );
        
        // 计算MD5
        try (FileInputStream fis = new FileInputStream(file.toFile())) {
            String md5 = DigestUtils.md5Hex(fis);
            metadata.setFileMd5(md5);
        }
        
        // 读取文件内容并提取元信息
        String content = Files.readString(file);
        metadata.setLineCount(content.split("\n").length);
        
        // 提取版权和许可证信息
        extractCopyrightInfo(content, metadata);
        
        return metadata;
    }
    
    /**
     * 提取版权和许可证信息
     */
    private void extractCopyrightInfo(String content, FileMetadata metadata) {
        String[] lines = content.split("\n", 50); // 只检查前50行
        
        StringBuilder copyright = new StringBuilder();
        StringBuilder license = new StringBuilder();
        StringBuilder authors = new StringBuilder();
        StringBuilder description = new StringBuilder();
        
        boolean inHeader = true;
        boolean foundCopyright = false;
        
        for (int i = 0; i < Math.min(lines.length, 50); i++) {
            String line = lines[i].trim();
            
            // 检查是否还在文件头注释中
            if (!line.startsWith("//") && !line.startsWith("/*") && 
                !line.startsWith("*") && !line.isEmpty()) {
                if (inHeader) {
                    inHeader = false;
                }
            }
            
            if (!inHeader && foundCopyright) {
                break;
            }
            
            String lowerLine = line.toLowerCase();
            
            // 提取版权信息
            if (lowerLine.contains("copyright") || lowerLine.contains("(c)") || 
                lowerLine.matches(".*\\d{4}.*huawei.*") || lowerLine.matches(".*\\d{4}.*ohos.*")) {
                copyright.append(line.replaceAll("^[/*\\s]+", "")).append("\n");
                foundCopyright = true;
            }
            
            // 提取许可证
            if (lowerLine.contains("license") || lowerLine.contains("licensed") ||
                lowerLine.contains("apache") || lowerLine.contains("bsd") || 
                lowerLine.contains("mit") || lowerLine.contains("gpl")) {
                license.append(line.replaceAll("^[/*\\s]+", "")).append("\n");
            }
            
            // 提取作者
            if (lowerLine.contains("author") || lowerLine.contains("@author")) {
                authors.append(line.replaceAll("^[/*\\s]+", "")).append("\n");
            }
            
            // 提取描述
            if (lowerLine.contains("@brief") || lowerLine.contains("@description") ||
                (lowerLine.startsWith("*") && lowerLine.length() > 10 && !lowerLine.contains("copyright"))) {
                description.append(line.replaceAll("^[/*\\s]+", "")).append("\n");
            }
        }
        
        if (copyright.length() > 0) {
            metadata.setCopyright(copyright.toString().trim());
        }
        if (license.length() > 0) {
            metadata.setLicense(license.toString().trim());
        }
        if (authors.length() > 0) {
            metadata.setAuthors(authors.toString().trim());
        }
        if (description.length() > 0) {
            metadata.setDescription(description.toString().trim());
        }
    }
    
    /**
     * 获取文件扩展名
     */
    private String getFileExtension(String fileName) {
        int lastDot = fileName.lastIndexOf('.');
        return lastDot > 0 ? fileName.substring(lastDot) : "";
    }
    
    /**
     * 计算目录深度
     */
    private int calculateDepth(String relativePath) {
        return relativePath.split("[\\\\/]").length - 1;
    }
    
    /**
     * 读取文件内容
     */
    public String readFileContent(String filePath) throws IOException {
        return Files.readString(Paths.get(filePath));
    }
}

